<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace buwang\service;

use Exception as ExceptionAlias;
use think\facade\Db;

class CrudService
{
    //图片上传接口地址
    private $upload_url = '/manage/publicCommon/upload';
    //数据库名
    private $table_schema = '';
    //数据库表前缀
    private $table_prefix = '';

    public function __construct()
    {
        $this->table_schema = config('database.connections.mysql.database');
        $this->table_prefix = config('database.connections.mysql.prefix');
    }

    /**
     * @param $app_name 应用的目录名如 bwmall
     * @param $table_name 数据库对应的表名如 bw_admin
     * @param string $controller_name_diy 控制器名
     * @param string $model_name_diy 模型名
     * @param array $relations 关联模型数组
     * @return bool
     * @throws ExceptionAlias
     */
    public function create($app_name, $table_name, &$controller_name_diy = '', &$model_name_diy = '', $relations = [])
    {
        //查询数据表是否存在
        $table_temp = Db::query("SHOW TABLE STATUS LIKE '{$table_name}'");
        if (!$table_temp) throw new ExceptionAlias("{$table_name}表不存在");

        $table = Db::table($table_name);
        //获取数据表的主键
        $pk = $table->getPk();
        if (!$pk) throw new ExceptionAlias("{$table_name}表无主键");
        //获取主表字段
        $table_field = $table->getFields();
        //不带表前缀的表名
        $model_table_name = $this->getModelTableName($table_name);
        //获取表备注
        $table_comment = $table_temp[0]['Comment'] ?: $model_table_name;
        $table_comment = mb_substr($table_comment, -1) == '表' ? mb_substr($table_comment, 0, -1) . '管理' : $table_comment;

        //默认的控制器名 模型名
        /*$controller_name_diy = $controller_name_diy ?: parse_name($model_table_name, 2);
        $model_name_diy = $model_name_diy ?: parse_name($model_table_name, 2);*/
        $this->getDiyName($table_name, $controller_name_diy, $model_name_diy);

        //有关联模型处理
        if (!empty($relations)) {
            foreach ($relations as $item) {
                //关联表是否存在
                $table = Db::query("SHOW TABLE STATUS LIKE '{$item['relation']}'");
                if (!$table) throw new ExceptionAlias("{$item['relation']}关联表不存在");

                //关联类型是否正确
                if (!in_array($item['relationmode'], ['belongsTo', 'hasOne'])) throw new ExceptionAlias("{$item['relation']}关联表关联类型有误");
                //关联表实例
                $item_table = Db::table($item['relation']);
                //获取关联表的主键
                $item_pk = $item_table->getPk();
                //获取关联表字段
                $item_table_field = $item_table->getFields();

                //belongsTo时关联外键在主表,关联主键在关联表 hasOne时关联外键在关联表,关联主键在主表
                if ($item['relationmode'] == 'belongsTo') {
                    //关联外键键是否存在
                    if (!isset($table_field[$item['relationforeignkey']])) throw new ExceptionAlias("{$item['relation']}关联表关联外键{$item['relationforeignkey']}不存在");
                    //关联主键是否存在
                    if (!isset($item_table_field[$item['relationprimarykey']])) throw new ExceptionAlias("{$item['relation']}关联表关联主键{$item['relationprimarykey']}不存在");
                } elseif ($item['relationmode'] == 'hasOne') {
                    //关联外键键是否存在
                    if (!isset($item_table_field[$item['relationforeignkey']])) throw new ExceptionAlias("{$item['relation']}关联表关联外键{$item['relationforeignkey']}不存在");
                    //关联主键是否存在
                    if (!isset($table_field[$item['relationprimarykey']])) throw new ExceptionAlias("{$item['relation']}关联表关联主键{$item['relationprimarykey']}不存在");
                }

                //显示字段是否存在
                $field_visible_arr = explode(',', $item['relationfields']);
                if (!empty(array_diff($field_visible_arr, array_keys($item_table_field)))) throw new ExceptionAlias("{$item['relation']}关联表显示字段有误");
            }
        }

        //写入菜单节点
        //$this->createMenu($app_name, $controller_name_diy, $table_comment);
        //生成模型Model文件
        $model_name = $this->createModel($app_name, $model_table_name, $model_name_diy, $pk, $relations);
        //生成控制器
        $this->createController($app_name, $controller_name_diy, $model_name, $relations);
        //TODO 生成html
        $this->createHtml($app_name, $table_name, $controller_name_diy, $relations);

        return true;
    }

    /**
     * TODO 生成菜单
     * @param $app_name
     * @param $controller_name_diy
     * @param $table_comment
     * @throws ExceptionAlias
     */
    private function createMenu($app_name, $controller_name_diy, $table_comment)
    {
        $app_auth_node = \app\manage\model\AuthNode::where('name', "/{$app_name}")->find();
        if (!$app_auth_node) throw new ExceptionAlias('菜单/{$app_name}未找到');

        //TODO 获取后台访问url
        $url = $this->getAdminUrl($app_name, $controller_name_diy);

        $param = [
            "pid" => $app_auth_node['id'],//TODO 上级菜单id,填0代表是顶部选项卡
            "title" => $table_comment,//菜单名称
            "app_name" => $app_name,//应用/插件名
            "type" => 'app',//TODO 权限分类 系统/应用/插件
            "menu_path" => $url,//后台url
            "name" => $url,//后台url
            "auth_name" => $url,//权限标识,必填
            "param" => "",//参数
            "target" => "_self",//打开方式
            "ismenu" => "1",//是否菜单
            "icon" => "",//图标
            "remark" => ""//备注
        ];
        //判断是否存在唯一标识
        $count = \app\manage\model\AuthNode::where('auth_name', $param['auth_name'])->count();
        if ($count) throw new ExceptionAlias('菜单已存在');

        Db::startTrans();
        try {
            //TODO 插入菜单记录
            $res = \app\manage\model\AuthNode::create($param);

            $params = [
                [
                    "pid" => $res->id,//TODO 上级菜单id,填0代表是顶部选项卡
                    "title" => '查看',//菜单名称
                    "app_name" => $app_name,//应用/插件名
                    "type" => 'app',//TODO 权限分类 系统/应用/插件
                    "menu_path" => $url . '/index',//后台url
                    "name" => $url . '/index',//后台url
                    "auth_name" => $url . '/index',//权限标识,必填
                    "param" => "",//参数
                    "target" => "_self",//打开方式
                    "ismenu" => "0",//是否菜单
                    "icon" => "",//图标
                    "remark" => ""//备注
                ],
                [
                    "pid" => $res->id,//TODO 上级菜单id,填0代表是顶部选项卡
                    "title" => '新增',//菜单名称
                    "app_name" => $app_name,//应用/插件名
                    "type" => 'app',//TODO 权限分类 系统/应用/插件
                    "menu_path" => $url . '/add',//后台url
                    "name" => $url . '/add',//后台url
                    "auth_name" => $url . '/add',//权限标识,必填
                    "param" => "",//参数
                    "target" => "_self",//打开方式
                    "ismenu" => "0",//是否菜单
                    "icon" => "",//图标
                    "remark" => ""//备注
                ],
                [
                    "pid" => $res->id,//TODO 上级菜单id,填0代表是顶部选项卡
                    "title" => '编辑',//菜单名称
                    "app_name" => $app_name,//应用/插件名
                    "type" => 'app',//TODO 权限分类 系统/应用/插件
                    "menu_path" => $url . '/edit',//后台url
                    "name" => $url . '/edit',//后台url
                    "auth_name" => $url . '/edit',//权限标识,必填
                    "param" => "",//参数
                    "target" => "_self",//打开方式
                    "ismenu" => "0",//是否菜单
                    "icon" => "",//图标
                    "remark" => ""//备注
                ],
                [
                    "pid" => $res->id,//TODO 上级菜单id,填0代表是顶部选项卡
                    "title" => '删除',//菜单名称
                    "app_name" => $app_name,//应用/插件名
                    "type" => 'app',//TODO 权限分类 系统/应用/插件
                    "menu_path" => $url . '/del',//后台url
                    "name" => $url . '/del',//后台url
                    "auth_name" => $url . '/del',//权限标识,必填
                    "param" => "",//参数
                    "target" => "_self",//打开方式
                    "ismenu" => "0",//是否菜单
                    "icon" => "",//图标
                    "remark" => ""//备注
                ],
            ];
            $authNode = new \app\manage\model\AuthNode;
            $authNode->saveAll($params);

            Db::commit();
        } catch (ExceptionAlias $e) {
            Db::rollback();
            throw $e;
        }
    }

    /**
     * 生成模型文件,Model.php
     * @param $app_name
     * @param $table_name
     * @param $model_name_diy
     * @return string
     * @throws ExceptionAlias
     */
    private function createModel($app_name, $model_table_name, $model_name_diy, $pk, $relations = [])
    {
        //关联模型方法
        $relation_function = '';
        //存在关联模型
        if (!empty($relations)) {
            foreach ($relations as $item) {
                $item_controller_name_diy = '';
                $item_model_name_diy = '';

                $this->getDiyName($item['relation'], $item_controller_name_diy, $item_model_name_diy);
                list($item_model_namespace, $item_model_class_name, $item_model_filepath) = $this->getModelAttr($app_name, $item_model_name_diy);

                //带命名空间的类名
                $item_model_class_name_full = "\\{$item_model_namespace}\\{$item_model_class_name}";
                //关联表尚未生成Model文件
                if (!class_exists($item_model_class_name_full)) {
                    //关联表
                    $item_table = Db::table($item['relation']);
                    //获取数据表的主键
                    $item_pk = $item_table->getPk();

                    $item_model_table_name = $this->getModelTableName($item['relation']);
                    $this->createModel($app_name, $item_model_table_name, $item_model_name_diy, $item_pk);
                }

                //TODO 向主表model中写入关联方法
                $relation_function .= "    public function " . lcfirst($item_model_class_name) . "(){
        return \$this->{$item['relationmode']}({$item_model_class_name_full}::class, '{$item['relationforeignkey']}', '{$item['relationprimarykey']}', [], 'LEFT');
    }" . PHP_EOL;
            }
        }

        //获取模型的命名空间和类名
        list($model_namespace, $model_class_name, $model_filepath) = $this->getModelAttr($app_name, $model_name_diy);

        //TODO 生成模型
        $model_template_path = root_path() . config('crud.model_php_template');
        if (!is_file($model_template_path)) throw new ExceptionAlias('模型模板文件不存在');
        // 参数
        $param = [
            'model_namespace' => $model_namespace,
            'model_class_name' => $model_class_name,
            'pk' => $pk,
            'model_table_name' => $model_table_name,
            'relation_function' => $relation_function,
        ];
        try {
            $this->writeFile($param, $model_template_path, $model_filepath);
        } catch (ExceptionAlias $e) {
            throw $e;
        }
        return "\\{$model_namespace}\\{$model_class_name}";
    }

    /**
     * 生成控制器文件,Controller.php
     * @param $app_name
     * @param $controller_name_diy
     * @param $model_name
     * @throws ExceptionAlias
     */
    private function createController($app_name, $controller_name_diy, $model_name, $relations = [])
    {
        if (!class_exists($model_name)) throw new ExceptionAlias('模型类不存在');

        $temp_class_name_str = '';
        //存在关联模型
        if (!empty($relations)) {
            $temp_class_name_arr = [];
            $temp_visible_str = '';
            foreach ($relations as $item) {
                $item_controller_name_diy = '';
                $item_model_name_diy = '';

                $this->getDiyName($item['relation'], $item_controller_name_diy, $item_model_name_diy);
                list($item_model_namespace, $item_model_class_name, $item_model_filepath) = $this->getModelAttr($app_name, $item_model_name_diy);

                $temp_class_name_arr[] = $item_model_class_name;

                $item_fields_str = $this->arrayToString(explode(',', $item['relationfields']));

                $temp_visible_str .= "                   \$row->getRelation('{$item_model_class_name}')->visible({$item_fields_str});" . PHP_EOL;
            }

            $temp_class_name_str = $this->arrayToString(array_map("lcfirst", $temp_class_name_arr));
        }

        //获取控制器的命名空间和类名
        list($controller_namespace, $controller_class_name, $controller_filepath) = $this->getControllerAttr($app_name, $controller_name_diy);
        //TODO 生成控制器
        $controller_template_path = root_path() . config('crud.controller_php_template');
        if (!is_file($controller_template_path)) throw new ExceptionAlias('控制器模板文件不存在');

        //TODO 整理参数
        $param = [
            'controller_namespace' => $controller_namespace,
            'controller_class_name' => $controller_class_name,
            'model_name' => $model_name,
            'temp_class_name_str' => $temp_class_name_str,
        ];
        try {
            $this->writeFile($param, $controller_template_path, $controller_filepath);
        } catch (ExceptionAlias $e) {
            throw $e;
        }
    }

    /**
     * 生成视图文件,index.html add.html edit.html
     * @param $app_name
     * @param $table_name
     * @param $controller_name_diy
     * @throws ExceptionAlias
     */
    private function createHtml($app_name, $table_name, $controller_name_diy, $relations = [])
    {
        //TODO 获取html文件生成路径
        if (strpos($controller_name_diy, '/') !== false) {//生成多级目录文件
            $array_reverse = array_reverse(array_filter(explode('/', $controller_name_diy)));
            if (empty($array_reverse)) throw new ExceptionAlias('控制器名有误');

            //TODO 把类名转换为 小写加下划线的形式
            $array_reverse[0] = parse_name($array_reverse[0]);

            //TODO 获取html文件最终生成基础路径
            $str_filepath = implode('/', array_reverse($array_reverse));
            $view_filepath_base = root_path() . "app/{$app_name}/view/{$str_filepath}/";//view文件不放在admin目录下 2020-5-30 16:43:46
        } else {
            //TODO 把类名转换为 小写加下划线的形式
            $temp_controller_name_diy = parse_name($controller_name_diy);
            //TODO 获取model文件最终生成路径
            $view_filepath_base = root_path() . "app/{$app_name}/view/{$temp_controller_name_diy}/";//view文件不放在admin目录下 2020-5-30 16:43:46
        }
        //把文件路径全部转为小写
        $view_filepath_base = strtolower($view_filepath_base);

        //获取数据表内容
        $table = Db::table($table_name);
        $pk = $table->getPk();//数据库的主键
        $field = $table->getFields();
        $pk_comment = $field[$pk]['comment'] ?: '序号';//主键注释

        //TODO 获取后台访问url
        $url = $this->getAdminUrl($app_name, $controller_name_diy);
        //新增的访问url
        $index_html_url_add = url($url . '/add', [], false)->build();
        //编辑的访问url
        $index_html_url_edit = url($url . '/edit', [], false)->build();
        //删除的访问url
        $index_html_url_del = url($url . '/del', [], false)->build();

        //index.html参数 $cols是layui-table的cols，$cols_template是layui-table的cols的template， $tool_event是layui-table的cols的lay-event，$layui_js是包含在layui use的js
        $cols = $cols_template = $tool_event = $layui_js = '';
        //add.html参数 中的html,js,submit_js代码
        $add_html_html = $add_html_js = $add_html_submit_js = '';
        //edit.html参数 中的html,js,submit_js代码
        $edit_html_html = $edit_html_js = $edit_html_submit_js = '';

        $sql = "SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = '{$this->table_schema}' AND table_name = '{$table_name}' ORDER BY ORDINAL_POSITION";
        $table_field = Db::query($sql);

        foreach ($table_field as $k => $v) {
            //获取数据库表字段对应列表内的展示类型 如 select
            $cols_type_temp = $this->getColsType($v);

            //获取数据库表字段对应列表内的html代码
            $this->getIndexContent($v, $cols, $cols_template, $tool_event, $layui_js, $cols_type_temp, $pk);

            //获取add.html页面的代码和js
            $this->getAddContent($v, $add_html_html, $add_html_js, $add_html_submit_js, $cols_type_temp);

            //获取edit.html页面的代码和js
            $this->getEditContent($v, $edit_html_html, $edit_html_js, $edit_html_submit_js, $cols_type_temp);
        }

        //TODO 关联模型
        if (!empty($relations)) {
            foreach ($relations as $item) {
                $sql = "SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = '{$this->table_schema}' AND table_name = '{$item['relation']}' ORDER BY ORDINAL_POSITION";
                $item_table_field = Db::query($sql);
                //关联模型要显示的字段是否存在
                $field_visible_arr = explode(',', $item['relationfields']);

                //获取数据表内容
                $table = Db::table($item['relation']);
                $pk = $table->getPk();//数据库的主键

                foreach ($field_visible_arr as $v) {
                    foreach ($item_table_field as $value) {
                        if ($value['COLUMN_NAME'] == $v) {//查询出关联模型中要显示的字段进行处理
                            //获取数据库表字段对应列表内的展示类型
                            $cols_type_temp = $this->getColsType($value);
                            //获取数据库表字段对应列表内的html代码
                            $this->getIndexContent($value, $cols, $cols_template, $tool_event, $layui_js, $cols_type_temp, $pk, $item);
                        }
                    }
                }
            }
        }

        //生成index.html
        $index_html_template_path = root_path() . config('crud.index_html_template');
        if (!is_file($index_html_template_path)) throw new ExceptionAlias('index视图文件不存在');

        //生成add.html
        $add_html_template_path = root_path() . config('crud.add_html_template');
        if (!is_file($add_html_template_path)) throw new ExceptionAlias('add视图文件不存在');

        //生成edit.html
        $edit_html_template_path = root_path() . config('crud.edit_html_template');
        if (!is_file($edit_html_template_path)) throw new ExceptionAlias('edit视图文件不存在');
        // 参数
        $param = [
            //index.html
            'pk' => $pk,
            'pk_comment' => $pk_comment,
            'cols' => $cols,
            'cols_template' => $cols_template,
            'tool_event' => $tool_event,
            'layui_js' => $layui_js,
            'url_add' => $index_html_url_add,
            'url_edit' => $index_html_url_edit,
            'url_del' => $index_html_url_del,
            //add.html
            'add_html_html' => $add_html_html,
            'add_html_js' => $add_html_js,
            'add_html_submit_js' => $add_html_submit_js,
            //adit.html
            'edit_html_html' => $edit_html_html,
            'edit_html_js' => $edit_html_js,
            'edit_html_submit_js' => $edit_html_submit_js,
        ];
        try {
            //TODO 如果没有view/public/base.html,还需要复制此文件
            $this->writeFile($param, $index_html_template_path, $view_filepath_base . 'index.html', true);
            $this->writeFile($param, $add_html_template_path, $view_filepath_base . 'add.html', true);
            $this->writeFile($param, $edit_html_template_path, $view_filepath_base . 'edit.html', true);
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 获取数据表内字段对应lay-table上字段的html内容
     * @param $item
     * @return string
     */
    private function getIndexContent($item, &$cols, &$cols_template, &$tool_event, &$layui_js, $cols_type = 'default', $pk = 'id', $relation = [])
    {
        $column_name = $item['COLUMN_NAME'];
        $column_comment = $item['COLUMN_COMMENT'] ?: $column_name;
        //$column_type = $item['DATA_TYPE'];

        //layui table col中的字段名,如果使用 user.id 会报错
        $column_name_col = $column_name;
        //js中的变量名,可以使用 user.id
        $column_name_js = $column_name;
        //有关联模型
        if (!empty($relation)) {
            //获取模型类名
            $this->getDiyName($relation['relation'], $relation_controller_name, $relation_model_name);

            $column_name_col = "{$relation_model_name}_{$column_name}";
            $column_name_js = "{$relation_model_name}.{$column_name}";
        }

        //TODO 跳过列表中不展示的字段类型
        if (in_array($cols_type, ['text'])) return true;
        //TODO 跳过列表中不展示的字段名称
        if (in_array($column_name_col, ['delete_time'])) return true;

        //主键列固定在左侧
        if ($item['COLUMN_KEY'] == 'PRI') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 80, fixed: 'left'}," . PHP_EOL;
            return true;
        }

        //默认html内容
        if ($cols_type == 'default') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', minWidth: 150, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ d.{$column_name_js} }}
                </script>" . PHP_EOL;
        }
        //列类型为单图
        if ($cols_type == 'image') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 60, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ getImagesHtmlForIndex(d.{$column_name_js}) }}
                </script>" . PHP_EOL;
        }
        //列类型为多图
        if ($cols_type == 'images') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 150, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ getImagesHtmlForIndex(d.{$column_name_js}) }}
                </script>" . PHP_EOL;
        }
        //列类型为数字
        if ($cols_type == 'number') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 80, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ d.{$column_name_js} }}
                </script>" . PHP_EOL;
        }
        //列类型为select
        if ($cols_type == 'select') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $temp_str = '';
            foreach ($itemArr as $k => $v) {
                if ($temp_str) $temp_str .= "
                    {{# } else if(d.{$column_name_js} == '{$k}') { }}
                    <span style=\"color: #1E9FFF;\">{$v}</span>";
                else $temp_str .= "
                    {{# if (d.{$column_name_js} == '{$k}') { }}
                    <span style=\"color: #1E9FFF;\">{$v}</span>";
            }

            if ($temp_str) $temp_str .= "
                    {{# } else { }}
                    <span style=\"color: #1E9FFF;\">{{d.{$column_name_js}}}</span>
                    {{# } }}";
            else $temp_str .= "
                    {{d.{$column_name_js}}}";

            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment_temp}', align: 'center', width: 100, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">{$temp_str}
                </script>" . PHP_EOL;
        }
        //列类型为开关
        if ($cols_type == 'switch') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment_temp}', align: 'center', width: 100, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    <input type=\"checkbox\" {{ d.{$column_name_js} == '1' ? 'checked' : '' }} name=\"{$column_name_js}\" value=\"{{d.{$pk}}}\" lay-skin=\"switch\" lay-filter=\"{$column_name_col}Change\" lay-text=\"{$itemArr['1']}|{$itemArr['0']}\">
                </script>" . PHP_EOL;
            $layui_js .= "        //监听{$column_name_col}开关
        form.on('switch({$column_name_col}Change)', function(obj){
            var state = this.checked ? '1' : '0';

            var {$pk} = obj.value;
            bwajax.post(ajax_edit + \"?{$pk}=\"+{$pk}, {{$pk}:{$pk},{$column_name_js}:state})
                .then(function (response) {
                    if (response.data.data.errcode === 0) {
                        layer.msg('修改成功', {icon: 1});
                    } else {
                        layer.msg(response.data.msg, {icon: 2});
                        reload();
                    }
                })
        });";
        }
        //列类型为时间
        if ($cols_type == 'time') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 160, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ formatDate(d.{$column_name_js}) }}
                </script>" . PHP_EOL;
        }
        //列类型为日期
        if ($cols_type == 'date') {
            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment}', align: 'center', width: 105, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">
                    {{ d.{$column_name_js} }}
                </script>" . PHP_EOL;
        }
        //列类型为多选
        if ($cols_type == 'multi') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $temp_str = '';
            foreach ($itemArr as $k => $v) {
                $temp_str .= "
                    {{# if (d.{$column_name_js}.search('$k') != -1) { }}
                    <span class='layui-badge'>{$v}</span>
                    {{# } }}";
            }
            if (!$temp_str) $temp_str .= "
                    {{d.{$column_name_js}}}";

            $cols .= "                {field: '{$column_name_col}', title: '{$column_comment_temp}', align: 'center', width: 150, templet: '#{$column_name_col}'}," . PHP_EOL;
            $cols_template .= "                <!--{$column_comment_temp}-->
                <script type=\"text/html\" id=\"{$column_name_col}\">{$temp_str}
                </script>" . PHP_EOL;
        }
        //TODO 列类型为单视频
        if ($cols_type == 'video') {
        }
        //TODO 列类型为多视频
        if ($cols_type == 'videos') {
        }
        //TODO 列类型为单文件
        if ($cols_type == 'file') {
        }
        //TODO 列类型为多文件
        if ($cols_type == 'files') {
        }
    }

    /**
     * 生成add.html的html和js
     * @param $item
     * @param $add_html_html
     * @param $add_html_js
     * @param string $cols_type
     * @return bool
     */
    private function getAddContent($item, &$add_html_html, &$add_html_js, &$submit_js, $cols_type = 'default')
    {
        $column_name = $item['COLUMN_NAME'];
        $column_comment = $item['COLUMN_COMMENT'] ?: $column_name;
        //$column_type = $item['DATA_TYPE'];

        //跳过主键
        if ($item['COLUMN_KEY'] == 'PRI') return true;
        //TODO 跳过不展示的字段类型
        //if (in_array($cols_type, [])) return true;
        //TODO 跳过不展示的字段名称
        if (in_array($column_name, ['create_time', 'update_time', 'delete_time'])) return true;

        //如果注释是需要解析的
        $column_comment_temp = $column_comment;
        //默认html内容
        if ($cols_type == 'default') $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"text\" name=\"{$column_name}\" placeholder=\"请输入{$column_comment}\" class=\"layui-input\" value=\"{$item['COLUMN_DEFAULT']}\"" . ($item['IS_NULLABLE'] == 'NO' ? " lay-verify='required'" : '') . ">
                        </div>
                    </div>" . PHP_EOL;

        //列类型为单图
        if ($cols_type == 'image') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单图</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认图片-->
                                    <script>
                                        getImagesHtmlForEdit('{$item['COLUMN_DEFAULT']}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;

            //2020-5-29 18:29:22 优化
            $add_html_js .= "        //{$column_comment}单图上传
        bw_upload(upload, '{$column_name}', 'image');" . PHP_EOL;
        }
        //列类型为多图
        if ($cols_type == 'images') {
            //('<img src="'+ res.data.data.src +'" class="layui-upload-img" style="width: 50px;height: 50px">');
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value=\"\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传多图</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认图片-->
                                    <script>
                                        getImagesHtmlForEdit('{$item['COLUMN_DEFAULT']}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;

            //2020-5-29 18:29:22 优化
            $add_html_js .= "        //{$column_comment}多图上传
        bw_upload(upload, '{$column_name}', 'images');" . PHP_EOL;
        }
        //列类型为数字
        if ($cols_type == 'number') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"number\" name=\"{$column_name}\" placeholder=\"请输入{$column_comment}\" class=\"layui-input\" value=\"{$item['COLUMN_DEFAULT']}\"" . ($item['IS_NULLABLE'] == 'NO' ? " lay-verify='required'" : '') . ">
                        </div>
                    </div>" . PHP_EOL;
        }
        //列类型为select
        if ($cols_type == 'select') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $option = "<option value=\"\" >请选择{$column_comment_temp}</option>";
            foreach ($itemArr as $k => $v) {
                //添加单选默认值
                if ($item['COLUMN_DEFAULT'] == $k) $option .= "
                                    <option value=\"{$k}\" selected>{$v}</option>";
                else $option .= "
                                    <option value=\"{$k}\">{$v}</option>";
            }

            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment_temp}</label>
                        <div class=\"layui-input-inline\" id=\"{$column_name}\">
                            <select name=\"{$column_name}\" lay-verify=\"required\">
                                {$option}
                            </select>
                        </div>
                    </div>" . PHP_EOL;
        }
        //列类型为开关
        if ($cols_type == 'switch') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <input id=\"{$column_name}\" type=\"hidden\" name=\"{$column_name}\" value=\"{$item['COLUMN_DEFAULT']}\">
                        <label class=\"layui-form-label\">{$column_comment_temp}</label>
                        <div class=\"layui-input-inline\">
                            <input id=\"{$column_name}_show\" type=\"checkbox\" " . ($item['COLUMN_DEFAULT'] == '1' ? 'checked' : '') . " value=\"{$item['COLUMN_DEFAULT']}\" lay-filter=\"{$column_name}Change\" lay-skin=\"switch\" lay-text=\"{$itemArr['1']}|{$itemArr['0']}\">
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //监听{$column_name}开关
        form.on('switch({$column_name}Change)', function(obj){
            var state = this.checked ? '1' : '0';
            
            layui.$('#{$column_name}_show').attr('value', state);
            layui.$('#{$column_name}').attr('value', state);
        });";
        }
        //列类型为 文本域或富文本
        if ($cols_type == 'text') {
            //文本域模式
//            $add_html_html .= "                    <!--{$column_comment}-->
//                    <div class=\"layui-form-item\">
//                        <label class=\"layui-form-label\">{$column_comment}</label>
//                        <div class=\"layui-input-block\">
//                            <textarea name='{$column_name}' placeholder='请输入{$column_comment}' class=\"layui-textarea\">{$item['COLUMN_DEFAULT']}</textarea>
//                        </div>
//                    </div>" . PHP_EOL;
            //富文本模式
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <script id=\"{$column_name}\" name=\"{$column_name}\" type=\"text/plain\" style=\"width:100%;height:500px;\"></script>
                            <script>
                                //实例化编辑器
                                UE.getEditor('{$column_name}');
                            </script>
                        </div>
                    </div>" . PHP_EOL;
        }
        //列类型为时间
        if ($cols_type == 'time') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-inline\">
                            <input id='{$column_name}'  type='text' name='{$column_name}' placeholder='请输入{$column_comment}' class='layui-input'" . ($item['IS_NULLABLE'] == 'NO' ? " lay-verify='required'" : '') . ">
                            <!--格式化时间-->
                            <script>
                                formatDate(\"{$item['COLUMN_DEFAULT']}\", '{$column_name}')
                            </script>
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //{$column_comment} 日期时间选择器
        laydate.render({
            elem: '#{$column_name}'
            ,type: 'datetime'
        });" . PHP_EOL;
            $submit_js .= "            //时间转为时间戳
            data.{$column_name} = Date.parse(data.{$column_name}) / 1000;" . PHP_EOL;
        }
        //列类型为日期
        if ($cols_type == 'date') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-inline\">
                            <input id='{$column_name}'  type='text' lay-verify='required' name='{$column_name}' placeholder='请输入{$column_comment}' class='layui-input' value='{$item['COLUMN_DEFAULT']}'>
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //{$column_comment} 日期选择器
        laydate.render({
            elem: '#{$column_name}'
        });" . PHP_EOL;
        }
        //列类型为多选 TODO 字段的默认值
        if ($cols_type == 'multi') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            //渲染多选具体元素的html
            $temp_html_str = '';
            //submit提交时判断多选元素是否被选中的js代码
            $temp_submit_str = '';
            foreach ($itemArr as $k => $v) {
                $temp_html_str .= "                            <input type='checkbox' name='{$column_name}_{$k}' lay-skin='primary' title='{$v}'>" . PHP_EOL;

                $temp_submit_str .= "            if(data.{$column_name}_{$k} && data.{$column_name}_{$k} == 'on') {
                {$column_name}.push('{$k}');
                delete data.{$column_name}_{$k};
            }" . PHP_EOL;
            }

            $add_html_html .= "                    <!--{$column_comment_temp}-->
                    <div class='layui-form-item'>
                        <label class='layui-form-label'>{$column_comment_temp}</label>
                        <div class='layui-input-block'>
{$temp_html_str}
                        </div>
                    </div>" . PHP_EOL;

            $submit_js .= "            //{$column_comment_temp} 多选转为字符串
            var {$column_name} = [];
{$temp_submit_str}
            data.{$column_name} = {$column_name}.join(',');" . PHP_EOL;
        }
        //列类型为单视频
        if ($cols_type == 'video') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单视频</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认视频-->
                                    <script>
                                        getVideoHtmlForEdit('{$item['COLUMN_DEFAULT']}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //{$column_comment}单视频上传
        bw_upload(upload, '{$column_name}', 'video');" . PHP_EOL;
        }
        //列类型为多视频
        if ($cols_type == 'videos') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value=\"\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传多视频</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认视频-->
                                    <script>
                                        getVideoHtmlForEdit('{$item['COLUMN_DEFAULT']}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //{$column_comment}多视频上传
        bw_upload(upload, '{$column_name}', 'videos');" . PHP_EOL;
        }
        //列类型为单文件
        if ($cols_type == 'file') {
            $add_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input class=\"layui-input layui-input-inline\" name=\"{$column_name}\" value='{$item['COLUMN_DEFAULT']}' placeholder=\"请上传{$column_comment}\" disabled style='width: 500px'>
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单文件</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: none;\">
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $add_html_js .= "        //{$column_comment}单文件上传
        bw_upload(upload, '{$column_name}', 'file');" . PHP_EOL;
        }
        //TODO 列类型为多文件
        if ($cols_type == 'files') {
        }

        //如果字段不为null,在ajax提交前进行参数验证
        if ($item['IS_NULLABLE'] == 'NO') $submit_js .= "            if(!data.{$column_name}) {layer.msg('{$column_comment_temp}不能为空', {icon: 2});return false}" . PHP_EOL;
    }

    /**
     * 生成edit.html的html和js
     * @param $item
     * @param $edit_html_html
     * @param $edit_html_js
     * @param string $cols_type
     * @return bool
     */
    private function getEditContent($item, &$edit_html_html, &$edit_html_js, &$submit_js, $cols_type = 'default')
    {
        $column_name = $item['COLUMN_NAME'];
        $column_comment = $item['COLUMN_COMMENT'] ?: $column_name;
        //$column_type = $item['DATA_TYPE'];

        //跳过主键
        if ($item['COLUMN_KEY'] == 'PRI') return true;
        //TODO 跳过不展示的字段类型
        //if (in_array($cols_type, [])) return true;
        //TODO 跳过不展示的字段名称
        if (in_array($column_name, ['create_time', 'update_time', 'delete_time'])) return true;

        //如果注释是需要解析的
        $column_comment_temp = $column_comment;
        //默认html内容
        if ($cols_type == 'default') $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"text\" name=\"{$column_name}\" placeholder=\"请输入{$column_comment}\" class=\"layui-input\" value=\"{\$row.{$column_name}}\">
                        </div>
                    </div>" . PHP_EOL;

        //列类型为单图
        if ($cols_type == 'image') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value='{\$row.{$column_name}}'>
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单图</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认图片-->
                                    <script>
                                        getImagesHtmlForEdit('{\$row.{$column_name}}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;

            //2020-5-29 18:29:22 优化
            $edit_html_js .= "        //{$column_comment}单图上传
        bw_upload(upload, '{$column_name}', 'image');" . PHP_EOL;
        }
        //列类型为多图
        if ($cols_type == 'images') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value=\"{\$row.{$column_name}}\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传多图</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认图片-->
                                    <script>
                                        getImagesHtmlForEdit('{\$row.{$column_name}}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;

            //2020-5-29 18:29:22 优化
            $edit_html_js .= "        //{$column_comment}多图上传
        bw_upload(upload, '{$column_name}', 'images');" . PHP_EOL;
        }
        //列类型为数字
        if ($cols_type == 'number') $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"number\" name=\"{$column_name}\" placeholder=\"请输入{$column_comment}\" class=\"layui-input\" value=\"{\$row.{$column_name}}\">
                        </div>
                    </div>" . PHP_EOL;
        //TODO 列类型为select
        if ($cols_type == 'select') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $option = "<option value=\"\" >请选择{$column_comment_temp}</option>";
            foreach ($itemArr as $k => $v) $option .= "
                                    <option value=\"{$k}\" {eq name=\"\$row.{$column_name}\" value=\"{$k}\"}selected{/eq}>{$v}</option>";

            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment_temp}</label>
                        <div class=\"layui-input-inline\" id=\"{$column_name}\">
                            <select name=\"{$column_name}\" lay-verify=\"required\">
                                {$option}
                            </select>
                        </div>
                    </div>" . PHP_EOL;
        }
        //TODO 列类型为开关
        if ($cols_type == 'switch') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            $edit_html_html .= "                    <!--{$column_comment}-->
                    <input id=\"{$column_name}\" type=\"hidden\" name=\"{$column_name}\" value='{\$row.{$column_name}}'>
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment_temp}</label>
                        <div class=\"layui-input-inline\">
                            <input id=\"{$column_name}_show\" type=\"checkbox\" {eq name=\"\$row.{$column_name}\" value=\"1\"}checked{/eq} lay-filter=\"{$column_name}Change\" value=\"{\$row.{$column_name}}\" lay-skin=\"switch\" lay-text=\"{$itemArr['1']}|{$itemArr['0']}\">
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //监听{$column_name}开关
        form.on('switch({$column_name}Change)', function(obj){
            var state = this.checked ? '1' : '0';
            
            layui.$('#{$column_name}_show').attr('value', state);
            layui.$('#{$column_name}').attr('value', state);
        });" . PHP_EOL;
        }
        //列类型为 文本域或富文本
        if ($cols_type == 'text') {
            //文本域模式
            /*$edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <textarea name='{$column_name}' placeholder=\"请输入{$column_comment}\" class=\"layui-textarea\">{\$row.{$column_name}}</textarea>
                        </div>
                    </div>" . PHP_EOL;*/
            //富文本模式
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <script id=\"{$column_name}\" name=\"{$column_name}\" type=\"text/plain\" style=\"width:100%;height:500px;\"></script>
                            <script>
                                //实例化编辑器
                                UE.getEditor('{$column_name}');
                                //格式化富文本
                                htmlDecode(\"{\$row.{$column_name}}\", '{$column_name}')
                            </script>
                        </div>
                    </div>" . PHP_EOL;
        }
        //列类型为时间
        if ($cols_type == 'time') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-inline\">
                            <input id='{$column_name}'  type='text' name='{$column_name}' placeholder='请输入{$column_comment}' class='layui-input'>
                            <!--格式化时间-->
                            <script>
                                formatDate(\"{\$row.{$column_name}}\", '{$column_name}')
                            </script>                            
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //{$column_comment} 日期时间选择器
        laydate.render({
            elem: '#{$column_name}'
            ,type: 'datetime'
        });" . PHP_EOL;
            $submit_js .= "            //时间转为时间戳
            data.{$column_name} = Date.parse(data.{$column_name}) / 1000;" . PHP_EOL;
        }
        //列类型为日期
        if ($cols_type == 'date') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-inline\">
                            <input id='{$column_name}'  type='text' lay-verify='required' name='{$column_name}' placeholder='请输入{$column_comment}' class='layui-input' value='{\$row.{$column_name}}'>                         
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //{$column_comment} 日期选择器
        laydate.render({
            elem: '#{$column_name}'
        });" . PHP_EOL;
        }
        //列类型为多选 TODO 字段的默认值
        if ($cols_type == 'multi') {
            $this->getDiyComment($column_comment, $column_comment_temp, $itemArr);

            //渲染多选具体元素的html
            $temp_html_str = '';
            //submit提交时判断多选元素是否被选中的js代码
            $temp_submit_str = '';
            foreach ($itemArr as $k => $v) {
                $temp_html_str .= "                            <input type='checkbox' name='{$column_name}_{$k}' lay-skin='primary' title='{$v}' {if false !== strpos(\$row.{$column_name}, '{$k}')}checked{/if}>" . PHP_EOL;

                $temp_submit_str .= "            if(data.{$column_name}_{$k} && data.{$column_name}_{$k} == 'on') {
                {$column_name}.push('{$k}');
                delete data.{$column_name}_{$k};
            }" . PHP_EOL;
            }

            $edit_html_html .= "                    <!--{$column_comment_temp}-->
                    <div class='layui-form-item'>
                        <label class='layui-form-label'>{$column_comment_temp}</label>
                        <div class='layui-input-block'>
{$temp_html_str}
                        </div>
                    </div>" . PHP_EOL;

            $submit_js .= "            //{$column_comment_temp} 多选转为字符串
            var {$column_name} = [];
{$temp_submit_str}
            data.{$column_name} = {$column_name}.join(',');" . PHP_EOL;
        }
        //列类型为单视频
        if ($cols_type == 'video') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value='{\$row.{$column_name}}'>
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单视频</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认视频-->
                                    <script>
                                        getVideoHtmlForEdit('{\$row.{$column_name}}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //{$column_comment}单视频上传
        bw_upload(upload, '{$column_name}', 'video');" . PHP_EOL;
        }
        //列类型为多视频
        if ($cols_type == 'videos') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input type=\"hidden\" name=\"{$column_name}\" class=\"layui-input\" value=\"{\$row.{$column_name}}\">
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传多视频</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: flex;\">
                                    <!--加载默认视频-->
                                    <script>
                                        getVideoHtmlForEdit('{\$row.{$column_name}}', '{$column_name}')
                                    </script>
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //{$column_comment}多视频上传
        bw_upload(upload, '{$column_name}', 'videos');" . PHP_EOL;
        }
        //列类型为单文件
        if ($cols_type == 'file') {
            $edit_html_html .= "                    <!--{$column_comment}-->
                    <div class=\"layui-form-item\">
                        <label class=\"layui-form-label\">{$column_comment}</label>
                        <div class=\"layui-input-block\">
                            <input class=\"layui-input layui-input-inline\" name=\"{$column_name}\" value='{\$row.{$column_name}}' placeholder=\"请上传{$column_comment}\" disabled style='width: 500px'>
                            <div class=\"layui-upload\">
                                <button type=\"button\" class=\"layui-btn layui-btn-normal\" id=\"{$column_name}\">上传单文件</button>
                                <div class=\"layui-upload-list\" id=\"{$column_name}Preview\" style=\"display: none;\">
                                </div>
                            </div>
                        </div>
                    </div>" . PHP_EOL;
            $edit_html_js .= "        //{$column_comment}单文件上传
        bw_upload(upload, '{$column_name}', 'file');" . PHP_EOL;
        }
        //TODO 列类型为多文件
        if ($cols_type == 'files') {
        }

        //如果字段不为null,在ajax提交前进行参数验证
        if ($item['IS_NULLABLE'] == 'NO') $submit_js .= "            if(!data.{$column_name}) {layer.msg('{$column_comment_temp}不能为空', {icon: 2});return false}" . PHP_EOL;
    }


    /**
     * 根据应用名和自定义控制器名获取控制器的命名空间 类型 文件地址
     * @param $app_name
     * @param $controller_name_diy
     * @return array
     * @throws ExceptionAlias
     */
    private function getControllerAttr($app_name, $controller_name_diy)
    {
        //TODO 获取控制器的命名空间和类名
//        $controller_namespace = "app\\{$app_name}\controller\admin";
        $controller_namespace = "app\\{$app_name}\controller";//controller文件不放在admin目录下 2020-5-30 16:43:46
        if (strpos($controller_name_diy, '/') !== false) {
            $array_reverse = array_reverse(array_filter(explode('/', $controller_name_diy)));
            if (empty($array_reverse)) throw new ExceptionAlias('控制器名有误');

            $controller_class_name = ucfirst($array_reverse[0]);
            unset($array_reverse[0]);
            $str = implode('\\', array_reverse($array_reverse));
            $controller_namespace .= "\\$str";

            //获取controller文件最终生成路径
            $str_filepath = implode('/', array_reverse($array_reverse));
//            $controller_filepath = root_path() . "app/{$app_name}/controller/admin/{$str_filepath}/{$controller_class_name}.php";
            $controller_filepath = root_path() . "app/{$app_name}/controller/{$str_filepath}/{$controller_class_name}.php";//controller文件不放在admin目录下 2020-5-30 16:43:46
        } else {
            $controller_class_name = ucfirst($controller_name_diy);

            //获取controller文件最终生成路径
//            $controller_filepath = root_path() . "app/{$app_name}/controller/admin/{$controller_class_name}.php";
            $controller_filepath = root_path() . "app/{$app_name}/controller/{$controller_class_name}.php";//controller文件不放在admin目录下 2020-5-30 16:43:46
        }
        $controller_namespace = strtolower($controller_namespace);

        return [$controller_namespace, $controller_class_name, $controller_filepath];
    }

    /**
     * 获取不带数据库表前缀的数据表名
     * @param $table_name
     * @return string
     */
    private function getModelTableName($table_name)
    {
        //数据库表前缀长度
        $table_prefix_length = mb_strlen($this->table_prefix, "utf-8");
        //不带表前缀的表名
        $model_table_name = mb_substr($table_name, 0, $table_prefix_length) == $this->table_prefix ? mb_substr($table_name, $table_prefix_length) : $table_name;
        return $model_table_name;
    }

    /**
     * 根据数据表名获取自定义的控制器名和模型名
     * @param $table_name
     * @param $controller_name_diy
     * @param $model_name_diy
     */
    private function getDiyName($table_name, &$controller_name_diy, &$model_name_diy)
    {
        $model_table_name = $this->getModelTableName($table_name);

        $controller_name_diy = $controller_name_diy ?: parse_name($model_table_name, 2);
        $model_name_diy = $model_name_diy ?: parse_name($model_table_name, 2);
    }

    /**
     * 根据应用名和自定义模型名获取Model文件的命名空间,类名,文件地址
     * @param $app_name
     * @param $model_name_diy
     * @return array
     * @throws ExceptionAlias
     */
    private function getModelAttr($app_name, $model_name_diy)
    {
        //获取模型的命名空间和类名
//        $model_namespace = "app\\{$app_name}\model\admin";
        $model_namespace = "app\\{$app_name}\model";//model文件不放在admin目录下 2020-5-30 16:43:46
        if (strpos($model_name_diy, '/') !== false) {//自定义模型名有目录分层
            $array_reverse = array_reverse(array_filter(explode('/', $model_name_diy)));
            if (empty($array_reverse)) throw new ExceptionAlias('模型名有误');

            $model_class_name = ucfirst($array_reverse[0]);//模型的类名
            unset($array_reverse[0]);
            $str = implode('\\', array_reverse($array_reverse));
            $model_namespace .= "\\$str";

            //获取model文件最终生成路径
            $str_filepath = implode('/', array_reverse($array_reverse));

            is_mkdir(root_path() . "app/{$app_name}/model/{$str_filepath}/");//判断目录是否存在并创建
            $model_filepath = root_path() . "app/{$app_name}/model/{$str_filepath}/{$model_class_name}.php";//model文件不放在admin目录下 2020-5-30 16:43:46
        } else {//自定义模型名没有目录分层
            $model_class_name = ucfirst($model_name_diy);//模型的类名

            // 获取model文件最终生成路径

            is_mkdir(root_path() . "app/{$app_name}/model/");//判断目录是否存在并创建
            $model_filepath = root_path() . "app/{$app_name}/model/{$model_class_name}.php";//model文件不放在admin目录下 2020-5-30 16:43:46
        }
        $model_namespace = strtolower($model_namespace);//模型的命名空间

        return [$model_namespace, $model_class_name, $model_filepath];
    }

    /**
     * 向项目中写入文件
     * @param array $param 模板替换参数
     * @param string $template_path 模板文件
     * @param string $filepath 文件写入路径
     * @param bool $is_html 是否生成Html文件
     * @return void
     * @throws ExceptionAlias
     */
    private function writeFile(array $param, string $template_path, string $filepath, bool $is_html = false)
    {
        // 拆解参数
        extract($param);
        // 开启缓冲区
        ob_start();
        // 引入模板文件
        require($template_path);
        // 获取缓冲区内容
        $out = ob_get_clean();
        //写入内容
        $File = new \think\template\driver\File();
        $File->write($filepath, $is_html ? $out : "<?php " . $out);
    }

    /**
     * 获取数据表内字段对应lay-table上字段的展示类型
     * @param $item
     * @return string
     */
    private function getColsType($item)
    {
        $column_name = $item['COLUMN_NAME'];//字段名
        //$column_comment = $item['COLUMN_COMMENT'] ?: $column_name;
        $column_type = $item['DATA_TYPE'];//字段类型

        $cols_type = 'default';

        //TODO 根据字段类型
        //文本输入框
        if (in_array($column_type, ['varchar'])) $cols_type = 'default';
        //数字输入框 TODO 整数 浮点应区分开,步长不一致
        if (in_array($column_type, ['tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint', 'float', 'double', 'decimal'])) $cols_type = 'number';
        //单选
        if (in_array($column_type, ['enum'])) $cols_type = 'select';
        //多选
        if (in_array($column_type, ['set'])) $cols_type = 'multi';
        //文本域 TODO 未完善富文本
        if (in_array($column_type, ['text'])) $cols_type = 'text';
        //日期选择
        if (in_array($column_type, ['date'])) $cols_type = 'date';

        //TODO 特殊字段
        //日期时间选择
        if (in_array($column_name, ['create_time', 'update_time', 'delete_time']) && $column_type == 'int') $cols_type = 'time';

        //TODO 以特殊字符结尾的规则
        //日期时间选择
        if (preg_match("/time$/i", $column_name) && $column_type == 'int') $cols_type = 'time';
        //单图
        if (preg_match("/image$/i", $column_name) && $column_type == 'varchar') $cols_type = 'image';
        if (preg_match("/avatar$/i", $column_name) && $column_type == 'varchar') $cols_type = 'image';
        //多图
        if (preg_match("/images$/i", $column_name) && $column_type == 'varchar') $cols_type = 'images';
        if (preg_match("/avatars$/i", $column_name) && $column_type == 'varchar') $cols_type = 'images';
        //开关
        if (preg_match("/switch$/i", $column_name) && $column_type == 'tinyint') $cols_type = 'switch';
        //单视频
        if (preg_match("/video$/i", $column_name) && $column_type == 'varchar') $cols_type = 'video';
        //多视频
        if (preg_match("/videos$/i", $column_name) && $column_type == 'varchar') $cols_type = 'videos';
        //单文件
        if (preg_match("/file$/i", $column_name) && $column_type == 'varchar') $cols_type = 'file';
        //多文件
        if (preg_match("/files$/i", $column_name) && $column_type == 'varchar') $cols_type = 'files';

        return $cols_type;
    }

    /**
     * 获取自定义的字段注释内容(状态:0=关闭,1=开启)
     * @param $column_comment 字段注释
     * @param $column_comment_temp 分离后的注释
     * @param $itemArr 数组格式的注释详情
     */
    private function getDiyComment($column_comment, &$column_comment_temp, &$itemArr)
    {
        list($column_comment_temp, $desc) = explode(':', $column_comment);
        foreach (explode(',', $desc) as $k => $v) {
            $valArr = explode('=', $v);
            if (count($valArr) == 2) {
                list($key, $value) = $valArr;
                $itemArr[$key] = $value;
            }
        }
    }

    /**
     * 把一维数组转为数组类型的string
     * @param $arr
     * @return string
     */
    private function arrayToString($arr)
    {
        $str = '';
        foreach ($arr as $item) {
            if (!$str) $str = "'{$item}'";
            else $str .= ",'{$item}'";
        }
        //$str = lcfirst($str);
        return "[{$str}]";
    }

    /**
     * 根据应用名和自定义控制器名获取 后台访问url,自行增加 /index /add /edit /del
     * @param $app_name
     * @param $controller_name_diy
     */
    private function getAdminUrl($app_name, $controller_name_diy)
    {
//        $url = "/{$app_name}/admin.";
        $url = "/{$app_name}/";//后台菜单不放在admin下 2020-5-30 16:43:46
        if (strpos($controller_name_diy, '/') !== false) {
//            $str = implode('.', array_filter(explode('/', $controller_name_diy)));
            //cc 2020-6-11 10:46:49 菜单内控制器名转为小驼峰
            $arr_temp_reverse = array_reverse(array_filter(explode('/', $controller_name_diy)));
            $arr_temp_reverse[0] = lcfirst($arr_temp_reverse[0]);//控制器名转为 小驼峰
            $str = implode('.', array_reverse($arr_temp_reverse));

            $url .= $str;
        } else {
            //cc 2020-6-11 10:46:49 菜单内控制器名转为小驼峰
            $url .= lcfirst($controller_name_diy);
        }

        return $url;
    }
}